import exrex, re, random, string
from datetime import datetime


class RuleAnalysis(object):

    _rule = None

    def __init__(self) -> None:
        pass

    def _setrule(self, rule_reg):
        self._rule = rule_reg
        return self

    def formatdate(self, exrex_str):
        date_format_map = {
            "yyyy": lambda: datetime.now().strftime("%Y"),
            "MM": lambda: datetime.now().strftime("%m"),
            "dd": lambda: datetime.now().strftime("%d"),
            "HH": lambda: datetime.now().strftime("%H"),
            "mm": lambda: datetime.now().strftime("%M"),
            "ss": lambda: datetime.now().strftime("%S"),
        }

        # 判断字符串中是否包含了date_format_map 的key
        keys = date_format_map.keys()
        if any(key in exrex_str for key in keys):
            # 通过 date_format_map 替换exrex_str命中规则
            for placeholder, formatter in date_format_map.items():
                exrex_str = exrex_str.replace(placeholder, formatter())

        return exrex_str

    def random_string(self, count=20, letters=True, numbers=False):
        if count <= 0:
            count = 20

        char_pool = ""

        if letters:
            char_pool += string.ascii_letters  # 包含所有字母
        if numbers:
            char_pool += string.digits  # 包含数字

        if not char_pool:  # 如果没有字母和数字
            char_pool = "".join(
                chr(i) for i in range(0, 0x110000)
            )  # 包含所有 Unicode 字符

        buffer = []

        while count > 0:
            ch = random.choice(char_pool)  # 随机选择字符
            buffer.append(ch)
            count -= 1

        return "".join(buffer)

    # 定义替换函数
    def format_uid(self, match):
        # 提取匹配到的数字
        try:
            number = match.group(1)
        except:
            number = 20

        # 转换为整数，若未匹配到则使用默认值20
        value = int(number) if number else 20
        return self.random_string(value, False, True)  # 返回替换后的字符串

    # 定义替换函数
    def format_ipv4(self, match):
        # IPv4 地址的正则表达式
        ipv4_pattern = r"(?:25[0-5]|2[0-4][0-9]|[1-9][0-9]?|0)\.(?:25[0-5]|2[0-4][0-9]|[1-9][0-9]?|0)\.(?:25[0-5]|2[0-4][0-9]|[1-9][0-9]?|0)\.(?:25[0-5]|2[0-4][0-9]|[1-9][0-9]?|0)"
        return exrex.getone(ipv4_pattern)  # 返回替换后的字符串

    def format_ipv6(self, match):
        # IPv6 地址的正则表达式
        # ipv6_pattern = r"((?:[0-9A-F]{1,4}:){7}[0-9A-F]{1,4}|(?:[0-9A-F]{1,4}:){1,7}:|(?:[0-9A-F]{1,4}:){1,6}:[0-9A-F]{1,4}|(?:[0-9A-F]{1,4}:){1,5}((:[0-9A-F]{1,4}){1,2}|:)|(?:[0-9A-F]{1,4}:){1,4}((:[0-9A-F]{1,4}){1,3}|:)|(?:[0-9A-F]{1,4}:){1,3}((:[0-9A-F]{1,4}){1,4}|:)|(?:[0-9A-F]{1,4}:){1,2}((:[0-9A-F]{1,4}){1,5}|:)|[0-9A-F]{1,4}:((:[0-9A-F]{1,4}){1,6}|:)|:((:[0-9A-F]{1,4}){1,7}|:)|FE80:(?:%[0-9A-Z]+)?|::1|::)"
        ipv6_pattern = r"([0-9A-F]{4}:){7}[0-9A-F]{4}"
        return exrex.getone(ipv6_pattern)  # 返回替换后的字符串

    # uid 替换
    def formatter(self, input_string, pattern, replacement):
        # 使用re.sub进行替换
        output_string = re.sub(pattern, replacement, input_string)
        return output_string

    def format_extra_str(self, exrex_str):
        # 定义正则表达式
        ipv4_search_pattern = r"ipv4"
        ipv6_search_pattern = r"ipv6"
        uid_search_pattern = r"uid(?:\((\d+)\))?"
        extra_format_map = {
            "ipv4": lambda: self.formatter(
                exrex_str, ipv4_search_pattern, self.format_ipv4
            ),
            "ipv6": lambda: self.formatter(
                exrex_str, ipv6_search_pattern, self.format_ipv6
            ),
            "uid": lambda: self.formatter(
                exrex_str, uid_search_pattern, self.format_uid
            ),
        }

        # 判断字符串中是否包含了date_format_map 的key
        keys = extra_format_map.keys()
        if any(key in exrex_str for key in keys):
            # 通过 date_format_map 替换exrex_str命中规则
            for placeholder, formatter in extra_format_map.items():
                if placeholder not in exrex_str:
                    continue

                exrex_str = formatter()

        return exrex_str

    def _mockstr(self):
        # 生成匹配给定正则表达式的第一个字符串
        exrex_str = "".join(exrex.getone(self._rule))
        # 格式化时间字符串
        exrex_str = self.formatdate(exrex_str)
        # 生成 其他类型参数
        exrex_str = self.format_extra_str(exrex_str)
        return exrex_str

    def _mocknum(self):
        # 生成匹配给定长度的数值 如果输入的并不是一个字符串 返回给定长度为1的数值
        exrex_num = None
        try:
            return str(float(self._rule)).rstrip("0").rstrip(".")
        except:
            try:
                length = int(self._rule)
            except:
                # 传递并不是数值 通过规则生成一个数字
                exrex_num = exrex.getone(self._rule)
                try:
                    float(exrex_num)
                except:
                    exrex_num = None
                    length = 1

        exrex_num = (
            exrex.getone((f"\\d{{{length}}}")) if exrex_num is None else exrex_num
        )

        if "." not in exrex_num:
            return str(int(exrex_num))
        return exrex_num.rstrip("0").rstrip(".")  # 使用 f-string 生成正则表达式

    def _mockdate(self):

        date_reg = r"(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) ([01]\d|2[0-3]):([0-5]\d):([0-5]\d)"
        if self._rule is None or self._rule == "":
            # 随机生成一个时间字符串
            self._rule = date_reg
        exrex_str = exrex.getone(self._rule)
        # 当前时间
        now = datetime.now()

        # 正则表达式模式
        pattern = r"(?P<year>\d{4})-(?P<month>0[1-9]|1[0-2])-(?P<day>0[1-9]|[12][0-9]|3[01])(?: (?P<hour>[01][0-9]|2[0-3]):(?P<minute>[0-5][0-9])(?::(?P<second>[0-5][0-9])(?:\.(?P<micro>[0-9]{3}))?)?)?"

        # 初始化结果字典
        result = {
            "yyyy": None,
            "MM": None,
            "dd": None,
            "HH": None,
            "mm": None,
            "ss": None,
            "SSS": None,
        }

        # 匹配用户输入
        matches = re.finditer(pattern, exrex_str)

        for match in matches:
            if match.group("year"):
                result["yyyy"] = match.group("year")
            if match.group("month"):
                result["MM"] = match.group("month")
            if match.group("day"):
                result["dd"] = match.group("day")
            if match.group("hour"):
                result["HH"] = match.group("hour")
            if match.group("minute"):
                result["mm"] = match.group("minute")
            if match.group("second"):
                result["ss"] = match.group("second")
            if match.group("micro"):
                result["SSS"] = match.group("micro")

        # 填充缺失的部分，使用当前时间
        result["yyyy"] = result["yyyy"] or str(now.year)
        result["MM"] = result["MM"] or f"{now.month:02}"
        result["dd"] = result["dd"] or f"{now.day:02}"
        result["HH"] = result["HH"] or f"{now.hour:02}"
        result["mm"] = result["mm"] or f"{now.minute:02}"
        result["ss"] = result["ss"] or f"{now.second:02}"
        result["SSS"] = result["SSS"] or f"{now.microsecond:03}"

        # 构造最终的时间字符串
        final_datetime = f"{result['yyyy']}-{result['MM']}-{result['dd']} {result['HH']}:{result['mm']}:{result['ss']}.{result['SSS']}"

        try:
            # 尝试解析字符串
            datetime.strptime(final_datetime, "%Y-%m-%d %H:%M:%S.%f")
            return final_datetime
        except ValueError:
            print("日期正则不正确，随机生成日期")
            return exrex.getone(date_reg)


# 注册对象
ruleAnalysis = RuleAnalysis()


def rule(rule_reg, ruleAnalysis: RuleAnalysis = None) -> None:
    """
    解析规则并模拟生成数据。

    参数:
    - rule_reg (str): 包含数据类型和规则的字符串，格式为 "数据类型@规则"。
    - ruleAnalysis (RuleAnalysis)：解析器对象

    支持的数据类型:
    - str: 字符串类型
    - date: 日期类型
    - int: 整数类型
    - none: 原文输出

    支持合并:
    通过&&符号 多项合并 形如 str@xxx&&date@yyyy-MM&&int@4

    str支持的规则:
    - 使用正则，输出一个完全匹配的字符串
    - 支持输入 yyyy 输出2024-10
    - 支持输入 MM 输出2024-10
    - 支持输入 dd 输出2024-10
    - 支持输入 HH 输出11
    - 支持输入 mm 输出24
    - 支持输入 ss 输出56
    - 支持输入任意拼接的上述格式 yyyy-MM-dd HH:mm:ss 输出2024-10-25 11:24:56
    - 支持生成唯一编号 uid uid(20) 输出20位随机串 如果没有数值，默认为20位长度 注意在应用括号的时候，进行转义
    - 支持生成IPV4地址 ipv4
    - 支持生成IPV6地址 ipv6

    date支持的规则
    - 允许输入日期正则
    - 支持输入 yyyy 输出2024
    - 支持输入 MM 输出10
    - 支持输入 dd 输出24
    - 支持输入 HH 输出11
    - 支持输入 mm 输出24
    - 支持输入 ss 输出56
    - 支持输入任意拼接的上述格式 yyyy-MM-dd HH:mm:ss 输出2024-10-25 11:24:56


    num支持的规则
    - 输入数值，用于控制字符串长度
    - 输入非数值，返回长度为1的数值
    - 输入数值正则，返回随机数值 支持 Number 格式


    返回:
    生成的数据，根据规则解析而来。
    """

    if not rule_reg:
        return ""

    pattern = r"(?P<str>str\s*@\s*[^&&]+)|(?P<date>date\s*@\s*[^&&]+)|(?P<num>num\s*@\s*[^&&]+)|(?P<none>none\s*@\s*[^&&]+)"

    # 查找所有匹配
    matches = list(re.finditer(pattern, rule_reg))

    # 判断是否有匹配内容
    if len(matches) < 1:
        return rule_reg  # 如果没有匹配，则返回原始字符串

    # 用于存储匹配结果
    results = []

    # 遍历所有匹配项
    for match in matches:
        # 获取匹配的分组
        for group_name, group_value in match.groupdict().items():
            if group_value:  # 只处理非空分组
                # 去除空白字符
                # if group_name != "none":
                #     group_value = re.sub(r"\s+", "", group_value)
                results.append(group_value)

    exrex_str = ""

    if ruleAnalysis is None:
        ruleAnalysis = RuleAnalysis()

    for sub_rule_reg in results:

        data_type, rule_str = sub_rule_reg.split("@", 1)

        rule_func = {
            "str": lambda rule: (ruleAnalysis._setrule(rule)._mockstr()),
            "date": lambda rule: (ruleAnalysis._setrule(rule)._mockdate()),
            "num": lambda rule: (ruleAnalysis._setrule(rule)._mocknum()),
            "none": lambda rule: rule,
        }

        keys = rule_func.keys()
        if any(key in data_type for key in keys) == False:
            exrex_str += sub_rule_reg
            continue

        # try:
        #     exrex_str += rule_func[data_type](rule_str)
        # except:
        #     exrex_str += sub_rule_reg

        exrex_str += rule_func[data_type](rule_str)

    return exrex_str if exrex_str != "" else rule_reg


__all__ = ["ruleAnalysis", "rule"]


if __name__ == "__main__":
    # print(rule("str@Mainuid\\(16\\)_uid\\(3\\)", ruleAnalysis))
    print(rule("date@2024-11-22", ruleAnalysis))
    # print(rule("num@-1", ruleAnalysis))

    # for i in range(40):
    #     print(rule("data@uid(16)", ruleAnalysis))
    pass
